package com.yuyou.hxyy.service.api.voice;

import com.alibaba.fastjson.TypeReference;
import com.yuyou.hxyy.service.api.enums.YouDaoEnums;
import com.yuyou.hxyy.service.api.exception.BusinessException;
import com.yuyou.hxyy.service.api.voice.vo.YoudaoResult;
import com.yuyou.hxyy.service.api.voice.vo.YoudaoTTVo;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;

import java.io.*;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.Map.Entry;


public class YoudaoApiUtils {

    private final static String appKey = "10c9bde2d01ece00";
    private final static String from = "EN";
    private final static String to = "EN";
    private final static String pass = "60fZ0qTBBs4m83OpgxVAFZACII1glqsc";
    private final static String youdaoUrl = "http://openapi.youdao.com/ttsapi";
    private final static String youdaoTTUrl = "http://openapi.youdao.com/ttsapi";


    /**
     * 获取文本翻译内容
     * 带发音url
     * @param query
     * @param voice
     * @return
     * @throws Exception
     */
    public static YoudaoResult getVoiceUrl(String query ,String voice) throws Exception {
        String salt = String.valueOf(System.currentTimeMillis());

        String sign = md5(appKey + query + salt+ pass);
        Map params = new HashMap();
        params.put("q", query);
        params.put("from", from);
        params.put("to", to);
        params.put("sign", sign);
        params.put("salt", salt);
        params.put("appKey", appKey);
        params.put("voice",voice);
        params.put("ext", "mp3");
        String result = requestForHttp(youdaoUrl, params);
        if(result == null){
            return null;
        }
        YoudaoResult r = com.alibaba.fastjson.JSONObject.parseObject(result, new TypeReference<YoudaoResult>(){});
        return r;
    }

    /**
     * 获取语音发音字节流
     * @param query
     * @param voice
     * @return
     */
    public static byte[] getVoice(String query ,Integer voice){
        Map<String, String> map = new HashMap<>();
        map.put("appKey", appKey);
        map.put("q",query);
        map.put("langType", "en");
        map.put("salt", String.valueOf(System.currentTimeMillis()));
        String sign = md5(
                map.get("appKey") + map.get("q") + map.get("salt") + pass);
        map.put("sign", sign);
        map.put("voice",voice+"");

        String ttsUrl = getUrlWithQueryString(youdaoTTUrl,map);
        /** 语音合成请求结果 */
        byte[] result = requestTTSorHttp(ttsUrl);
        return result;
    }

    /*public static void main(String[] args) throws Exception {
        Map<String, String> map = new HashMap<>();
        String url = "http://openapi.youdao.com/ttsapi";
        int et = 0;
        map.put("appKey", appKey);
        String q = "eduction";
        map.put("q",q);
        map.put("langType", "en");
        map.put("salt", String.valueOf(System.currentTimeMillis()));
        String sign = md5(
                map.get("appKey") + map.get("q") + map.get("salt") + pass);
        map.put("sign", sign);
        map.put("voice","5");

        String ttsUrl = getUrlWithQueryString(url,map);
        byte[] result = requestTTSorHttp(ttsUrl);
        if(result != null){//合成成功
            String file = "/Users/yuan/Desktop/6.mp3";
            byte2File(result,file);
        }

    }*/

    /**
     * 将字节流存储为文件
     * @param result 音频字节流
     * @param file 存储路径
     */
    private static void byte2File(byte[] result, String file) {
        File audioFile = new File(file);
        FileOutputStream fos = null;
        try{
            fos = new FileOutputStream(audioFile);
            fos.write(result);

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 请求语音合成服务
     * @param ttsUrl
     * @return
     */
    private static byte[] requestTTSorHttp(String ttsUrl) {
        byte[] result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(ttsUrl);
        CloseableHttpResponse httpResponse = null;
        try{
            httpResponse = httpClient.execute(httpGet);
            Header[] contentType = httpResponse.getHeaders("Content-Type");
            if("audio/mp3".equals(contentType[0].getValue())){//如果响应是wav
                HttpEntity httpEntity = httpResponse.getEntity();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                httpResponse.getEntity().writeTo(baos);
                result = baos.toByteArray();
                EntityUtils.consume(httpEntity);
            }else{
                /** 响应不是音频流，直接显示结果 */
                HttpEntity httpEntity = httpResponse.getEntity();
                String json = EntityUtils.toString(httpEntity,"UTF-8");
                EntityUtils.consume(httpEntity);
                YoudaoTTVo y = com.alibaba.fastjson.JSONObject.parseObject(json, new TypeReference<YoudaoTTVo>(){});
                String errResult;
                if(y.getErrorCode() == YouDaoEnums.ErrorCode.Arrearage.getId()){
                    errResult = YouDaoEnums.ErrorCode.Arrearage.getName();
                }else if(y.getErrorCode() == YouDaoEnums.ErrorCode.TooFrequent.getId()){
                    errResult = YouDaoEnums.ErrorCode.TooFrequent.getName();
                }else {
                    errResult = YouDaoEnums.ErrorCode.OtherErr.getName();
                }
                throw new BusinessException(errResult);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try{
                if(httpResponse != null){
                    httpResponse.close();
                }
            }catch (Exception e){
                e.printStackTrace();
//                logger.info("## release resouce error ##" + e);
            }
        }
        return result;
    }

    /**
     * 请求文本翻译
     * @param url
     * @param requestParams
     * @return
     * @throws Exception
     */
    public static String requestForHttp(String url,Map requestParams) throws Exception{
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        /**HttpPost*/
        HttpPost httpPost = new HttpPost(url);
        System.out.println(new JSONObject(requestParams).toString());
        List params = new ArrayList();
        Iterator<Entry> it = requestParams.entrySet().iterator();
        while (it.hasNext()) {
            Entry en = it.next();
            String key = (String) en.getKey();
            String value = (String) en.getValue();
            if (value != null) {
                params.add(new BasicNameValuePair(key, value));
            }
        }
        httpPost.setEntity(new UrlEncodedFormEntity(params,"UTF-8"));
        /**HttpResponse*/
        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        try{
            HttpEntity httpEntity = httpResponse.getEntity();
            result = EntityUtils.toString(httpEntity, "utf-8");
            EntityUtils.consume(httpEntity);
        }finally{
            try{
                if(httpResponse!=null){
                    httpResponse.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 生成32位MD5摘要
     * @param string
     * @return
     */
    public static String md5(String string) {
        if(string == null){
            return null;
        }
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                'A', 'B', 'C', 'D', 'E', 'F'};

        try{
            byte[] btInput = string.getBytes("utf-8");
            /** 获得MD5摘要算法的 MessageDigest 对象 */
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            /** 使用指定的字节更新摘要 */
            mdInst.update(btInput);
            /** 获得密文 */
            byte[] md = mdInst.digest();
            /** 把密文转换成十六进制的字符串形式 */
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (byte byte0 : md) {
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        }catch(NoSuchAlgorithmException | UnsupportedEncodingException e){
            return null;
        }
    }

    /**
     * 根据api地址和参数生成请求URL
     * @param url
     * @param params
     * @return
     */
    public static String getUrlWithQueryString(String url, Map<String , String> params) {
        if (params == null) {
            return url;
        }

        StringBuilder builder = new StringBuilder(url);
        if (url.contains("?")) {
            builder.append("&");
        } else {
            builder.append("?");
        }

        int i = 0;
        for (String key : params.keySet()) {
            String value = params.get(key);
            if (value == null) { // 过滤空的key
                continue;
            }

            if (i != 0) {
                builder.append('&');
            }

            builder.append(key);
            builder.append('=');
            builder.append(encode(value));

            i++;
        }

        return builder.toString();
    }
    /**
     * 进行URL编码
     * @param input
     * @return
     */
    public static String encode(String input) {
        if (input == null) {
            return "";
        }

        try {
            return URLEncoder.encode(input, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return input;
    }
}
